// +build linux

package io_uring

import (
	"sync/atomic"

	iouring_syscall "gitee.com/childewang/iouring-go/syscall"
)

// SubmissionQueue ...
type SubmissionQueue struct {
	ptr uintptr

	head        *uint32
	tail        *uint32
	ringMask    *uint32
	ringEntries *uint32
	flags       *uint32
	dropped     *uint32
	array       []uint32
	sqes        []iouring_syscall.IOUringSQE
	sqeHead     uint32
	sqeTail     uint32
	size        uint32
}

func (sq *SubmissionQueue) getSQE() *iouring_syscall.IOUringSQE {
	head := atomic.LoadUint32(sq.head)
	next := sq.sqeTail + 1

	if (next - head) > *sq.ringEntries {
		return nil
	}
	sqe := &sq.sqes[sq.sqeTail&*sq.ringMask]
	sq.sqeTail = next
	return sqe
}

func (queue *SubmissionQueue) fallback(i uint32) {
	queue.sqeTail -= i
}

func (sq *SubmissionQueue) cqOverflow() bool {
	return (atomic.LoadUint32(sq.flags) & iouring_syscall.IORING_SQ_CQ_OVERFLOW) != 0
}

func (queue *SubmissionQueue) needWakeup() bool {
	return (atomic.LoadUint32(queue.flags) & iouring_syscall.IORING_SQ_NEED_WAKEUP) != 0
}

func (sq *SubmissionQueue) flush() int {
	tail := *sq.tail
	mask := *sq.ringMask
	toSubmit := sq.sqeTail - sq.sqeHead

	if toSubmit <= 0 {
		return int(tail - *sq.head)
	}

	for ; toSubmit > 0; toSubmit-- {
		sq.array[tail&mask] = sq.sqeHead & mask
		tail++
		sq.sqeHead++
	}

	atomic.StoreUint32(sq.tail, tail)
	return int(tail - *sq.head)
}
